// 观察者模式
// 观察者模式（Observer Pattern）是一种行为设计模式，
// 它定义了一种一对多的依赖关系，让多个观察者对象同时监听某一个主题对象。
// 这个主题对象在状态发生变化时，会通知所有观察者对象，使它们能够自动更新自己。
// 注意点：是主题对象主动添加观察者（自愿被观察）

// 1. 定义观察者接口
// 定义方法，但不做具体方法实现，由子类实现
class Observer {
  update(message) {
    throw new Error("子类必须实现 update 方法");
  }
}

// 2. 实现具体的观察者
class ConcreteObserverA extends Observer {
  update(message) {
    console.log("ConcreteObserverA 收到消息: " + message);
  }
}

class ConcreteObserverB extends Observer {
  update(message) {
    console.log("ConcreteObserverB 收到消息: " + message);
  }
}

// 3. 定义主题接口
class Subject {
    // 添加观察者
  addObserver(observer) {
    throw new Error("子类必须实现 addObserver 方法");
  }

//   移除观察者
  removeObserver(observer) {
    throw new Error("子类必须实现 removeObserver 方法");
  }
//   通知观察者
  notifyObservers() {
    throw new Error("子类必须实现 notifyObservers 方法");
  }
}

// 4. 实现具体的主题
class ConcreteSubject extends Subject {
  constructor() {
    super();
    this.observers = []; //观察者列表
    this.state = null;
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
    }
  }

  notifyObservers() {
    for (let observer of this.observers) {
      observer.update(this.state);
    }
  }

  setState(state) {
    this.state = state;
    this.notifyObservers();
  }

  getState() {
    return this.state;
  }
}

// 5. 使用观察者模式
const subject = new ConcreteSubject();

const observerA = new ConcreteObserverA();
const observerB = new ConcreteObserverB();

subject.addObserver(observerA);
subject.addObserver(observerB);

// 观察者观察到主题对象发生状态变化，则会自动调用自己的方法。
subject.setState("新状态1"); // ConcreteObserverA 收到消息: 新状态1, ConcreteObserverB 收到消息: 新状态1
subject.setState("新状态2"); // ConcreteObserverA 收到消息: 新状态2, ConcreteObserverB 收到消息: 新状态2

subject.removeObserver(observerA);

subject.setState("新状态3"); // ConcreteObserverB 收到消息: 新状态3
subject.removeObserver(observerB);  
subject.setState("新状态4");  //此时主体对象已经没有观察者,所有状态发生变化不会有任何观察者的通知
// console.log(subject.getState());  //打印subject的state


